package cpu.datastores;

import cpu.datatypes.*;

public class Register32 {
	private static final int LENGTH = 32;
	
	public Register16 wordLow;
	public Register16 wordHigh;
	
	public Register32( ) {
		wordLow = new Register16( );
		wordHigh = new Register16( );
	}
	public Bit bit( int i ) {
		assert( i >= 0 && i < 32 );
		
		if( i >= 0 && i <= 15  )
			return wordLow.bit( i );	// 0 : little endian
		return wordHigh.bit( i - 16 );
	}
	public Register16 register( int i ) {
		if( i == 0 )
			return wordLow;
		return wordHigh;
	}
	public int toJavaInt( ) {
		int accumulator = 0;

		for( int i = 0; i < 16; i++ ) {
			if( wordLow.bit( i ).value )
				accumulator += java.lang.Math.pow( 2, i );
		}
		for( int i = 0; i < 16; i++ ) {
			if( wordHigh.bit( i ).value )
				accumulator += java.lang.Math.pow( 2, i + 16 );
		}
		
		return accumulator;
	}
	public boolean fromJavaInt( int value ) {
		// note return value is overflow
		int accumulator = value;
		
		if( value < 0 ) {
			accumulator = -accumulator;
			wordHigh.bit( 0 ).value = true;				
		} else {
			wordHigh.bit( 0 ).value = false;
		}
		
		for( int i = 15; i >= 0; i-- ) {
			if( accumulator / java.lang.Math.pow( 2, i + 16 ) >= 1 ) {
				wordHigh.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i + 16 );
			} else {
				wordHigh.bit( i ).value = false;
			}
		}
		for( int i = 15; i >= 0; i-- ) {
			if( accumulator / java.lang.Math.pow( 2, i ) >= 1 ) {
				wordLow.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i );
			} else {
				wordLow.bit( i ).value = false;
			}
		}

		if( accumulator != 0 ) 
			return true;		// overflow
		return false;			// no overflow			
	}
	public int toSignedInteger( ) {
		int accumulator = 0;

		boolean negative = false;
		if( wordHigh.bit( 0 ).value )
			negative = true;
		
		for( int i = 0; i < 16; i++ ) {
			if( wordLow.bit( i ).value )
				accumulator += java.lang.Math.pow( 2, i );
		}
		for( int i = 1; i < 16; i++ ) {
			if( wordHigh.bit( i ).value )
				accumulator += java.lang.Math.pow( 2, i - 1 + 16 );
		}
		
		if( negative )
			accumulator = -accumulator;
		
		return accumulator;
	}
	public boolean fromLongInteger( cpu.datatypes.LongInteger n ) {
		int accumulator = n.toJavaInt( );
		
		boolean negative = false;
		
		if( accumulator < 0 ) {
			negative = true;
			accumulator = -accumulator;
		}
		
		for( int i = 15; i >= 1; i-- ) {
			if( accumulator / (int) java.lang.Math.pow( 2, i - 1 + 16 ) >= 1 ) {
				wordHigh.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i - 1 + 16 );
			} else {
				wordHigh.bit( i ).value = false;
			}
		}
		for( int i = 15; i >= 0; i-- ) {
			if( accumulator / (int) java.lang.Math.pow( 2, i ) >= 1 ) {
				wordLow.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i );
			} else {
				wordLow.bit( i ).value = false;
			}
		}

		if( negative ) {
			twoscomplementinline( );
			wordHigh.bit( 0 ).value = true;				
		} else {
			wordHigh.bit( 0 ).value = false;
		}
		
		if( accumulator != 0 ) 
			return true;		// overflow
		return false;			// no overflow
	}
	public boolean fromSignedInteger( cpu.datatypes.Integer n ) {
		int accumulator = n.toJavaInt( );
		
		boolean negative = false;
		
		if( accumulator < 0 ) {
			negative = true;
			accumulator = -accumulator;
		}
		
		for( int i = 15; i >= 1; i-- ) {
			if( accumulator / (int) java.lang.Math.pow( 2, i - 1 + 16 ) >= 1 ) {
				wordHigh.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i - 1 + 16 );
			} else {
				wordHigh.bit( i ).value = false;
			}
		}
		for( int i = 15; i >= 0; i-- ) {
			if( accumulator / (int) java.lang.Math.pow( 2, i ) >= 1 ) {
				wordLow.bit( i ).value = true;
				accumulator -= java.lang.Math.pow( 2, i );
			} else {
				wordLow.bit( i ).value = false;
			}
		}

		if( negative ) {
			twoscomplementinline( );
			wordHigh.bit( 0 ).value = true;				
		} else {
			wordHigh.bit( 0 ).value = false;
		}
		
		if( accumulator != 0 ) 
			return true;		// overflow
		return false;			// no overflow
	}
	private void twoscomplementinline( ) {
		// two's complement
		boolean carry = false;
		for( int i = 0; i < 31; i++ ) {
			if( !carry ) {
				if( i < 16 ) {
					if( bit( i ).value == true )
						carry = true;
				} else {
					if( bit( i + 1 ).value == true )
						carry = true;
				}
			} else {
				if( i < 16 ) {
					bit( i ).value = !bit( i ).value;
				} else {
					bit( i + 1 ).value = !bit( i + 1 ).value;
				}
			}
		}
	}
	private DoubleWord twoscomplement( ) {
		// two's complement
		
		DoubleWord result = new DoubleWord( );
		result.wordHigh.fromRegister( wordHigh );
		result.wordLow.fromRegister( wordLow );
		
		boolean carry = false;
		for( int i = 0; i < 31; i++ ) {
			if( !carry ) {
				if( i < 16 ) {
					if( result.bit( i ).value == true )
						carry = true;
				} else {
					if( result.bit( i + 1 ).value == true )
						carry = true;
				}
			} else {
				if( i < 16 ) {
					result.bit( i ).value = !result.bit( i ).value;
				} else {
					result.bit( i + 1 ).value = !result.bit( i + 1 ).value;
				}
			}
		}
		return result;
	}
}
